package com.smartmedi.ai.utils;

import java.io.*;
import java.nio.ByteBuffer;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.nio.charset.CodingErrorAction;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;

/**
 * 中文编码处理工具类
 * 用于解决中文文本乱码问题，可用于任何Java项目
 * 
 * @author MediMind
 */
public class ChineseEncodingUtils {

    /**
     * 常用中文编码集合
     */
    private static final String[] CHINESE_ENCODINGS = {
            "UTF-8", "GBK", "GB2312", "GB18030", "BIG5", "ISO-8859-1", "Windows-1252"
    };

    /**
     * 修复乱码文本
     * @param text 可能包含乱码的文本
     * @return 修复后的文本
     */
    public static String fixGarbledText(String text) {
        if (text == null || text.isEmpty()) {
            return text;
        }

        // 检查是否包含乱码
        if (containsGarbledChars(text)) {
            // 尝试使用各种编码组合修复
            String result = tryCommonEncodingPaths(text);
            if (!containsGarbledChars(result)) {
                return result;
            }

            // 尝试修复双重编码问题
            result = tryFixDoubleEncoding(text);
            if (!containsGarbledChars(result)) {
                return result;
            }
            
            // 尝试字节级解码
            result = tryByteByByteDecoding(text);
            if (!containsGarbledChars(result)) {
                return result;
            }
        }

        // 无法修复，返回原文本
        return text;
    }

    /**
     * 尝试各种常见编码修复路径
     */
    private static String tryCommonEncodingPaths(String text) {
        for (String sourceEncoding : CHINESE_ENCODINGS) {
            try {
                // 假设文本是以sourceEncoding编码后被当做UTF-8解读的
                byte[] bytes = text.getBytes(StandardCharsets.UTF_8);
                String decodedText = new String(bytes, sourceEncoding);
                
                // 再次以正确的编码转为UTF-8
                bytes = decodedText.getBytes(sourceEncoding);
                String fixedText = new String(bytes, StandardCharsets.UTF_8);
                
                // 如果修复后的文本不再含有乱码字符，则认为修复成功
                if (!containsGarbledChars(fixedText)) {
                    return fixedText;
                }
            } catch (Exception ignored) {
                // 忽略异常，尝试下一个编码
            }
        }
        return text;
    }

    /**
     * 尝试修复双重编码问题
     */
    private static String tryFixDoubleEncoding(String text) {
        for (String encoding1 : CHINESE_ENCODINGS) {
            for (String encoding2 : CHINESE_ENCODINGS) {
                if (encoding1.equals(encoding2)) continue;
                
                try {
                    // 尝试逆向转换可能的双重编码
                    byte[] bytes = text.getBytes(StandardCharsets.UTF_8);
                    String intermediate = new String(bytes, encoding1);
                    bytes = intermediate.getBytes(encoding1);
                    String result = new String(bytes, encoding2);
                    
                    if (!containsGarbledChars(result)) {
                        return result;
                    }
                } catch (Exception ignored) {
                    // 忽略异常，继续尝试
                }
            }
        }
        return text;
    }

    /**
     * 尝试字节级别的解码，适用于混合编码情况
     */
    private static String tryByteByByteDecoding(String text) {
        try {
            byte[] bytes = text.getBytes();
            StringBuilder sb = new StringBuilder(text.length());
            
            for (int i = 0; i < bytes.length; i++) {
                // 检测可能的中文字符（GBK/GB2312编码）
                if (i < bytes.length - 1) {
                    int b1 = bytes[i] & 0xFF;
                    int b2 = bytes[i+1] & 0xFF;
                    
                    // GBK可能的字节范围
                    if ((b1 >= 0x81 && b1 <= 0xFE) && 
                        ((b2 >= 0x40 && b2 <= 0x7E) || (b2 >= 0x80 && b2 <= 0xFE))) {
                        try {
                            String s = new String(new byte[]{bytes[i], bytes[i+1]}, "GBK");
                            sb.append(s);
                            i++; // 跳过下一个字节
                            continue;
                        } catch (Exception ignored) {
                            // 解码失败，按单字节处理
                        }
                    }
                }
                
                // 单字节处理
                sb.append((char)(bytes[i] & 0xFF));
            }
            
            String result = sb.toString();
            if (!containsGarbledChars(result)) {
                return result;
            }
        } catch (Exception ignored) {
            // 忽略异常
        }
        
        return text;
    }

    /**
     * 读取文件内容，自动处理编码问题
     * @param file 要读取的文件
     * @return 文件内容
     * @throws IOException 读取异常
     */
    public static String readFileWithCorrectEncoding(File file) throws IOException {
        // 尝试检测文件编码
        String detectedEncoding = detectFileEncoding(file);
        if (detectedEncoding != null) {
            try {
                String content = readFileWithEncoding(file, detectedEncoding);
                if (!containsGarbledChars(content)) {
                    return content;
                }
            } catch (IOException ignored) {
                // 尝试下一种方法
            }
        }
        
        // 如果检测失败或读取有乱码，尝试所有可能的编码
        return tryAllEncodings(file);
    }

    /**
     * 使用指定编码读取文件
     * @param file 文件
     * @param encoding 编码
     * @return 文件内容
     * @throws IOException 读取异常
     */
    public static String readFileWithEncoding(File file, String encoding) throws IOException {
        try (BufferedReader reader = new BufferedReader(
                new InputStreamReader(new FileInputStream(file), encoding))) {
            
            StringBuilder sb = new StringBuilder();
            String line;
            while ((line = reader.readLine()) != null) {
                sb.append(line).append("\n");
            }
            
            return sb.toString();
        }
    }

    /**
     * 尝试所有可能的编码读取文件
     * @param file 文件
     * @return 文件内容
     * @throws IOException 读取异常
     */
    private static String tryAllEncodings(File file) throws IOException {
        String content = null;
        IOException lastException = null;
        
        for (String encoding : CHINESE_ENCODINGS) {
            try {
                content = readFileWithEncoding(file, encoding);
                
                // 如果读取的内容没有明显的乱码字符，则认为找到了正确的编码
                if (!containsGarbledChars(content)) {
                    return content;
                }
            } catch (IOException e) {
                lastException = e;
                // 继续尝试
            }
        }
        
        // 如果所有编码都尝试过，但仍然有乱码，返回最后一次读取的内容
        if (content != null) {
            return content;
        }
        
        // 如果所有尝试都失败，抛出最后一个异常
        if (lastException != null) {
            throw lastException;
        }
        
        throw new IOException("无法读取文件内容");
    }

    /**
     * 检测文件编码
     * @param file 文件
     * @return 检测到的编码，如果无法检测返回null
     */
    public static String detectFileEncoding(File file) {
        try (FileInputStream fis = new FileInputStream(file)) {
            // 读取文件头部字节
            byte[] buffer = new byte[Math.min(4096, (int)file.length())];
            int read = fis.read(buffer);
            buffer = Arrays.copyOf(buffer, read);
            
            // 检测BOM标记
            String bomEncoding = checkBOM(buffer);
            if (bomEncoding != null) {
                return bomEncoding;
            }
            
            // 尝试通过统计特征检测编码
            return detectEncodingByFeatures(buffer);
        } catch (IOException ignored) {
            return null;
        }
    }

    /**
     * 检查BOM标记来确定编码
     */
    private static String checkBOM(byte[] bytes) {
        if (bytes.length >= 3 && bytes[0] == (byte)0xEF && bytes[1] == (byte)0xBB && bytes[2] == (byte)0xBF) {
            return "UTF-8";
        }
        if (bytes.length >= 2 && bytes[0] == (byte)0xFE && bytes[1] == (byte)0xFF) {
            return "UTF-16BE";
        }
        if (bytes.length >= 2 && bytes[0] == (byte)0xFF && bytes[1] == (byte)0xFE) {
            return "UTF-16LE";
        }
        if (bytes.length >= 4 && bytes[0] == (byte)0x00 && bytes[1] == (byte)0x00 && 
            bytes[2] == (byte)0xFE && bytes[3] == (byte)0xFF) {
            return "UTF-32BE";
        }
        if (bytes.length >= 4 && bytes[0] == (byte)0xFF && bytes[1] == (byte)0xFE && 
            bytes[2] == (byte)0x00 && bytes[3] == (byte)0x00) {
            return "UTF-32LE";
        }
        return null;
    }

    /**
     * 通过字节特征检测编码
     */
    private static String detectEncodingByFeatures(byte[] bytes) {
        // 检查是否为UTF-8
        if (isValidUTF8(bytes)) {
            return "UTF-8";
        }
        
        // 检查是否可能是GBK/GB18030
        if (isPossibleGBK(bytes)) {
            return "GB18030"; // GB18030 是超集，包含 GBK 和 GB2312
        }
        
        // 如果无法确定，默认返回系统默认编码
        return Charset.defaultCharset().name();
    }

    /**
     * 检查字节序列是否是有效的UTF-8
     */
    private static boolean isValidUTF8(byte[] bytes) {
        CharsetDecoder decoder = StandardCharsets.UTF_8.newDecoder()
            .onMalformedInput(CodingErrorAction.REPORT)
            .onUnmappableCharacter(CodingErrorAction.REPORT);
        
        try {
            decoder.decode(ByteBuffer.wrap(bytes));
            return true;
        } catch (Exception e) {
            return false;
        }
    }

    /**
     * 检查字节序列是否可能是GBK编码
     */
    private static boolean isPossibleGBK(byte[] bytes) {
        int gbkChars = 0;
        int totalChars = 0;
        
        for (int i = 0; i < bytes.length; i++) {
            int b = bytes[i] & 0xFF;
            
            // 单字节字符
            if (b <= 0x7F) {
                totalChars++;
                continue;
            }
            
            // 可能是GBK双字节字符的第一个字节
            if (b >= 0x81 && b <= 0xFE && i < bytes.length - 1) {
                int b2 = bytes[i+1] & 0xFF;
                
                // GBK双字节字符的第二个字节范围
                if ((b2 >= 0x40 && b2 <= 0x7E) || (b2 >= 0x80 && b2 <= 0xFE)) {
                    gbkChars++;
                    totalChars++;
                    i++; // 跳过下一个字节
                } else {
                    totalChars++;
                }
            } else {
                totalChars++;
            }
        }
        
        // 如果GBK特征字符占比较高，可能是GBK编码
        return totalChars > 0 && (double)gbkChars / totalChars > 0.1;
    }

    /**
     * 将字符串从一种编码转换为另一种编码
     * @param text 原始文本
     * @param fromEncoding 源编码
     * @param toEncoding 目标编码
     * @return 转换后的文本
     */
    public static String convertEncoding(String text, String fromEncoding, String toEncoding) {
        if (text == null || text.isEmpty()) {
            return text;
        }
        
        try {
            byte[] bytes = text.getBytes(fromEncoding);
            return new String(bytes, toEncoding);
        } catch (UnsupportedEncodingException e) {
            return text;
        }
    }

    /**
     * 判断文本是否包含乱码字符
     * @param text 要检查的文本
     * @return 是否包含乱码字符
     */
    public static boolean containsGarbledChars(String text) {
        if (text == null || text.isEmpty()) {
            return false;
        }
        
        // 乱码字符计数
        int garbledCount = 0;
        int chineseCount = 0;
        
        for (int i = 0; i < text.length(); i++) {
            char c = text.charAt(i);
            
            // 检测中文字符
            if (isChinese(c)) {
                chineseCount++;
            }
            
            // 常见乱码字符
            if (c == '�' || c == '□' || c == '?' || 
                (c >= 0xFFFD && c <= 0xFFFF) || // Unicode 替换字符
                (c >= 0x80 && c <= 0x9F && c != 0x9D)) { // 控制字符
                garbledCount++;
            }
        }
        
        // 乱码比例阈值
        double garbledThreshold = 0.05;
        
        // 如果乱码字符超过阈值，认为存在乱码
        boolean hasGarbledChars = garbledCount > text.length() * garbledThreshold;
        
        // 如果文本应该包含中文但实际上没有，也可能是乱码
        boolean shouldHaveChinese = text.length() > 10 && text.matches(".*[\u4E00-\u9FA5].*");
        boolean lacksExpectedChinese = shouldHaveChinese && chineseCount < text.length() * 0.1;
        
        return hasGarbledChars || lacksExpectedChinese;
    }
    
    /**
     * 判断字符是否是中文
     * @param c 字符
     * @return 是否是中文
     */
    public static boolean isChinese(char c) {
        Character.UnicodeBlock ub = Character.UnicodeBlock.of(c);
        return ub == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS
            || ub == Character.UnicodeBlock.CJK_COMPATIBILITY_IDEOGRAPHS
            || ub == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS_EXTENSION_A;
    }

    /**
     * 检测字节数组中有效UTF-8字符的数量
     * @param data 字节数组
     * @return UTF-8字符占比
     */
    public static double detectUTF8Ratio(byte[] data) {
        int utf8Count = 0;
        int totalBytes = 0;
        
        for (int i = 0; i < data.length; i++) {
            totalBytes++;
            
            // 单字节ASCII
            if ((data[i] & 0x80) == 0) {
                utf8Count++;
                continue;
            }
            
            // 检测多字节UTF-8序列
            if ((data[i] & 0xE0) == 0xC0) { // 2字节序列
                if (i + 1 < data.length && (data[i + 1] & 0xC0) == 0x80) {
                    utf8Count += 2;
                    i += 1;
                }
            } else if ((data[i] & 0xF0) == 0xE0) { // 3字节序列
                if (i + 2 < data.length && (data[i + 1] & 0xC0) == 0x80 && (data[i + 2] & 0xC0) == 0x80) {
                    utf8Count += 3;
                    i += 2;
                }
            } else if ((data[i] & 0xF8) == 0xF0) { // 4字节序列
                if (i + 3 < data.length && (data[i + 1] & 0xC0) == 0x80 && 
                    (data[i + 2] & 0xC0) == 0x80 && (data[i + 3] & 0xC0) == 0x80) {
                    utf8Count += 4;
                    i += 3;
                }
            }
        }
        
        return totalBytes > 0 ? (double) utf8Count / totalBytes : 0;
    }
    
    /**
     * 从字节数组自动检测编码并转换为字符串
     * @param data 字节数组
     * @return 转换后的字符串
     */
    public static String bytesToString(byte[] data) {
        if (data == null || data.length == 0) {
            return "";
        }
        
        try {
            // 检查BOM头标记
            String bomEncoding = checkBOM(data);
            if (bomEncoding != null) {
                try {
                    return new String(data, bomEncoding);
                } catch (UnsupportedEncodingException e) {
                    // 回退到其他检测方法
                }
            }
            
            // 检测UTF-8概率
            double utf8Ratio = detectUTF8Ratio(data);
            if (utf8Ratio > 0.8) {
                try {
                    String result = new String(data, StandardCharsets.UTF_8);
                    if (!containsGarbledChars(result)) {
                        return result;
                    }
                } catch (Exception e) {
                    // 忽略并继续尝试其他编码
                }
            }
            
            // 尝试常用中文编码
            for (String encoding : CHINESE_ENCODINGS) {
                try {
                    String result = new String(data, encoding);
                    if (!containsGarbledChars(result)) {
                        return result;
                    }
                } catch (Exception e) {
                    // 忽略并继续尝试
                }
            }
            
            // 如果所有尝试都失败，使用系统默认编码
            return new String(data);
        } catch (Exception e) {
            // 发生任何异常，使用系统默认编码作为回退方案
            return new String(data);
        }
    }
} 